﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Smile.Network.Http
{
    /// <summary>Object to send basical http requests.</summary>
    ///
    /// <example>
    ///     var request = new HttpRequest();
    ///     var response = await request.GetAsync("http://www.kittyful.com");
    /// </example>
    public class HttpRequest : IHttpRequest
    {
        // @Public
        /// <summary>
        ///     Send a GET request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri">The Uri the request is sent to.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> GetAsync(string uri)
        {
            try
            {
                HttpClient client = new HttpClient();
                var response = await client.GetAsync(uri);
                return await ReadResponse(response);
            }
            catch
            {
                return new HttpResponse();
            }
        }

        /// <summary>
        ///     Send a GET request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri">The Uri the request is sent to.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> GetAsync(Uri uri)
        {
            try
            {
                HttpClient client = new HttpClient();
                var response = await client.GetAsync(uri);
                return await ReadResponse(response);
            }
            catch
            {
                return new HttpResponse();
            }
        }

        /// <summary>
        ///     Send a POST request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri"> The Uri the request is sent to.</param>
        /// <param name="data">The data to be post.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> PostAsync(string uri, IDictionary<string, string> data)
        {
            try
            {
                HttpClient client = new HttpClient();
                var response = await client.PostAsync(uri, new FormUrlEncodedContent(data));
                return await ReadResponse(response);
            }
            catch (Exception)
            {
                return new HttpResponse();
            }
        }

        /// <summary>
        ///     Send a POST request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri"> The Uri the request is sent to.</param>
        /// <param name="data">The data to be post.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> PostAsync(Uri uri, IDictionary<string, string> data)
        {
            try
            {
                HttpClient client = new HttpClient();
                var response = await client.PostAsync(uri, new FormUrlEncodedContent(data));
                return await ReadResponse(response);
            }
            catch
            {
                return new HttpResponse();
            }
        }

        /// <summary>
        ///     Send a PUT request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri"> The Uri the request is sent to.</param>
        /// <param name="data">The data to be post.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> PutAsync(string uri, IDictionary<string, string> data)
        {
            try
            {
                HttpClient client = new HttpClient();
                var response = await client.PutAsync(uri, new FormUrlEncodedContent(data));
                return await ReadResponse(response);
            }
            catch
            {
                return new HttpResponse();
            }
        }

        /// <summary>
        ///     Send a PUT request to the specified Uri as an asynchronous operation.
        /// </summary>
        ///
        /// <param name="uri"> The Uri the request is sent to.</param>
        /// <param name="data">The data to be post.</param>
        ///
        /// <returns>The task object representing the asynchronous operation.</returns>
        public async Task<HttpResponse> PutAsync(Uri uri, IDictionary<string, string> data)
        {
            HttpClient client = new HttpClient();
            var response = await client.PutAsync(uri, new FormUrlEncodedContent(data));
            return await ReadResponse(response);
        }

        /// <summary>Generates a data string content.</summary>
        ///
        /// <param name="data">The data to be post.</param>
        ///
        /// <returns>The data string content.</returns>
        public static string GenerateDataStringContent(IDictionary<string, string> data)
        {
            string postString = string.Empty;
            foreach (var entry in data)
            {
                postString += entry.Key + '=';
                postString += entry.Value + '&';
            }
            postString = postString.TrimEnd('&');
            return postString;
        }


        // @Private
        async Task<HttpResponse> ReadResponse(HttpResponseMessage response)
        {
            var httpResponse = new HttpResponse();
            httpResponse.Status = response.StatusCode;
            if (response.Content.Headers.ContentLength > 0)
            {
                httpResponse.ContentBytes = await response.Content.ReadAsByteArrayAsync();
            }
            return httpResponse;
        }
    }
}
